<template>
  <div ref="containerRef"></div>
</template>

<script setup lang="ts">
import { onMounted, PropType, ref } from 'vue'
import {
  PerspectiveCamera,
  Scene,
  AmbientLight,
  PointLight,
  WebGLRenderer,
  Box3,
  Vector3,
  Object3D,
} from 'three'

import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

const props = defineProps({
  objSrc: {
    type: String,
    default: '',
  },
  mtlSrc: {
    type: String,
    default: '',
  },
  files: {
    type: Array as PropType<
      {
        name: string
        url: string
      }[]
    >,
    default: () => [],
  },
})

const containerRef = ref()

let camera: PerspectiveCamera, scene: Scene, renderer
// 正则过滤掉除数字、字母、_、-、.外的字符
// const reg = /[^\u4e00-\u9fa5a-zA-Z0-9-_.]/g
const reg = /[^A-Za-z0-9_]/g
// const reg = /[^\u4e00-\u9fa5a-zA-Z0-9-_.]/g

function init() {
  camera = new PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    0.1,
    20,
  )
  camera.position.z = 2.5

  // scene

  scene = new Scene()

  const ambientLight = new AmbientLight(0xffffff, 1)
  scene.add(ambientLight)

  const pointLight = new PointLight(0xffffff, 1)
  camera.add(pointLight)
  scene.add(camera)

  // model

  const onProgress = function (xhr) {
    if (xhr.lengthComputable) {
      const percentComplete = (xhr.loaded / xhr.total) * 100
      console.log(percentComplete.toFixed(2) + '% downloaded')
    }
  }
  new MTLLoader().load(props.mtlSrc, function (materials) {
    // mtl文件中有kd（漫反射）为0的材质，模型无法正常显示，显示为黑色，手动设置为白色
    for (const key in materials.materialsInfo) {
      if (materials.materialsInfo[key]?.kd?.every((e) => e === 0)) {
        materials.materialsInfo[key].kd = [1, 1, 1]
      }
      if (materials.materialsInfo[key].map_kd) {
        const currentFile = props.files.find((file) => {
          const arr = file.name.split('/')
          const fileName = arr[arr.length - 1]
          const mapKdArr = materials.materialsInfo[key].map_kd!.split('\\')
          const mapKdName = mapKdArr[mapKdArr.length - 1]
          console.log(fileName, mapKdName)
          console.log(fileName.replace(reg, ''), mapKdName.replace(reg, ''))
          return fileName.replace(reg, '') === mapKdName.replace(reg, '')
        })
        if (currentFile) {
          const strArr = currentFile.url.split('/')
          materials.materialsInfo[key].map_kd = strArr[strArr.length - 1]
        }
      }
      if (materials.materialsInfo[key].bump) {
        const paramsArr = materials.materialsInfo[key].bump!.split(' ')
        const currentFile = props.files.find((file) => {
          const arr = file.name.split('/')
          const fileName = arr[arr.length - 1]
          const mapBumpPath = paramsArr[paramsArr.length - 1]
          const mapBumpArr = mapBumpPath.split('\\')
          const mapKdName = mapBumpArr[mapBumpArr.length - 1]
          return fileName.replace(reg, '') === mapKdName.replace(reg, '')
        })
        if (currentFile) {
          const strArr = currentFile.url.split('/')
          paramsArr.pop()
          materials.materialsInfo[key].bump = [
            ...paramsArr,
            strArr[strArr.length - 1],
          ].join(' ')
        }
      }
    }
    console.log(materials)
    materials.preload()

    new OBJLoader().setMaterials(materials).load(
      props.objSrc,
      function (object) {
        const size = getObjectSize(object)
        const maxSize = Math.max(size.x, size.y, size.z)
        const scale = 1 / maxSize
        object.scale.setScalar(scale)
        scene.add(object)
        console.log(camera.position)
      },
      onProgress,
    )
  })

  //

  renderer = new WebGLRenderer({ antialias: true, alpha: true })
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setAnimationLoop(animate)
  containerRef.value.appendChild(renderer.domElement)

  const controls = new OrbitControls(camera, renderer.domElement)
  controls.minDistance = 0.2
  // controls.maxDistance = 50

  window.addEventListener('resize', onWindowResize)
}

// 获取模型尺寸信息
function getObjectSize(model: Object3D) {
  const box = new Box3().setFromObject(model)
  const size = box.getSize(new Vector3())
  return size
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
}

function animate() {
  renderer.render(scene, camera)
}

onMounted(() => {
  init()
})
</script>

<style scoped lang="scss"></style>
